'use strict';

var orgnizationImpl = require('./dao_impl/orgnization.js');
var ferror = require('../common/app_utils.js').formatError;
var fout = require('../common/app_utils.js').formatOutput;
var errInfo = require('../common/err_info.js');
var debug = require('debug')('dao_orgnization');

function MongoDao() {
	var self = this instanceof MongoDao ? this : new MongoDao();
	return self;
}

module.exports = new MongoDao();
var theProto = MongoDao.prototype;

/*
{
"name":"root", 
"description":"总部",
"path":[]
}

{
"name":"tianhe", 
"description":"总部->华东区->广东省->广州市->天河区",
"path":["id1","id2","id3","id4"]
}
*/
theProto.create = function(json) {
	return orgnizationImpl.create(json);
};

/*create a tree, isRoot must be true
{
	"name": "xx",
	"description": "xx",
	"isRoot": "true", <==============
	"sub": [{
		"name": "xx",
		"description": "xx",
		"sub": [...]
	}, {
		"name": "xx",
		"description": "xx",
		"sub": [...]
	}]
}*/
theProto.createTree = function(json) {
	return orgnizationImpl.createTree(json);
};

theProto.readById = function(id) {
	return orgnizationImpl.readById(id);
};

/*
{
	orgnization:xxid
	vendor:{set:[xxid,xxid]}
}

{
	orgnization:xxid
	vendor:{add:[xxid,xxid]}
}

{
	orgnization:xxid
	vendor:{remove:[xxid,xxid]}
}
*/
theProto.updateVendor = function(json) {
	var operation = {
		query: {
			_id: json.orgnization
		},
		update: {}
	};

	if (json.vendors.set && json.vendors.set.length > 0) {
		operation.update['$set'] = {
			vendors: json.vendors.set
		};
	} else if (json.vendors.add && json.vendors.add.length > 0) {
		operation.update['$addToSet'] = {
			vendors: {
				$each: json.vendors.add
			}
		};
	} else if (json.vendors.remove && json.vendors.remove.length > 0) {
		operation.update['$pull'] = {
			vendors: {
				$in: json.vendors.remove
			}
		};
	}
	// debug('operation', JSON.stringify(operation));
	return orgnizationImpl.update(operation);
};

theProto.readAsTree = function(json) {
	// TODO userId check permission

	// find all, then build a tree
	return orgnizationImpl.read({})

	.then(function(result) {
		debug('all orgnization', result.result);
		if (result.errCode !== 0) return result;
		var tree = __composeTree(result.result);
		debug('tree result \n', JSON.stringify(tree));
		return fout(tree);
	});
};

// compose nodes to a tree
function __composeTree(nodeArray) {
	debug('__composeTree', nodeArray);
	var tree = [];

	nodeArray.forEach(function(item) {
		addToTree(item);
	});
	return tree;

	function addToTree(aNode) {
		aNode = aNode.toObject();
		aNode.sub = [];
		// debug('\n\naddToTree-------------------');
		// debug('add node', JSON.stringify(aNode));
		// debug('now tree', JSON.stringify(tree));
		if (tree.length === 0) return addFirstNode(aNode);

		var ids = aNode.path || [];
		var stop = false;
		var foundCount = 0;
		var found = false;
		var currId;
		var currArr = tree;
		var j = 0;
		while (!stop) {
			currId = ids[foundCount];
			if (!currId) break;

			found = false;
			// found currId in currArr
			for (j = 0; j < currArr.length; j++) {
				var item = currArr[j];
				// debug('item=', JSON.stringify(item));
				if (item._id.toString() === currId.toString()) {
					// debug('found id =', currId);
					foundCount += 1;
					found = true;
					if (!item.sub) item.sub = [];
					currArr = item.sub;
					break;
				}
			}

			if (!found) {
				stop = true;
			}
		}

		for (j = foundCount; j < ids.length; j++) {
			var id = ids[j];
			// debug('add virtual node', id);
			var tmpNode = createTmpNode(id);
			currArr.push(tmpNode);
			currArr = tmpNode.sub;
		}

		var mockTarget = null;
		var mockIndex = -1;
		for (j = 0; j < currArr.length; j++) {
			if (currArr[j]._id === aNode._id) {
				mockTarget = currArr[j];
				mockIndex = j;
				break;
			}
		}
		if (mockTarget) {
			currArr.splice(mockIndex, 1);
			aNode.sub = mockTarget.sub;
		}
		currArr.push(aNode);
	}

	function addFirstNode(aNode) {
		var path = aNode.path;
		var currParent = null;
		var firstNode = null;
		if (path && path.length > 0) {
			path.forEach(function(id) {
				var node = createTmpNode(id);
				if (currParent) {
					currParent.sub.push(node);
				}
				if (!firstNode) {
					firstNode = node;
				}
				currParent = node;
			});
			currParent.sub.push(aNode);
		} else {
			firstNode = aNode;
		}

		tree.push(firstNode);
	}

	function createTmpNode(id) {
		return {
			_id: id,
			__tmp: true,
			sub: []
		};
	}
}